package com.idealighter.game.games.doudizhu.manager;

import com.google.inject.Inject;
import com.google.inject.Singleton;

import com.idealighter.game.dictionary.dic.DoudizhuMatchRoomDic;
import com.idealighter.game.dictionary.dic.DoudizhuRoomTypeDic;
import com.idealighter.game.dictionary.dic.ItemDic;
import com.idealighter.game.dictionary.domain.DoudizhuMatchRoomDomain;
import com.idealighter.game.dictionary.domwrapper.DoudizhuMatchRoomDomWrapper;
import com.idealighter.game.dictionary.domwrapper.DoudizhuMatchRoomDomWrapper.Reward;
import com.idealighter.game.games.common.AbstractSeat;
import com.idealighter.game.games.doudizhu.dto.BillInfo;
import com.idealighter.game.games.doudizhu.dto.MatchInfo;
import com.idealighter.game.games.doudizhu.dto.RankRewardInfo;
import com.idealighter.game.games.doudizhu.dto.RoomInfo;
import com.idealighter.game.games.doudizhu.dto.RoomTypeDetailInfo;
import com.idealighter.game.games.doudizhu.message.ResAbandonMsg;
import com.idealighter.game.games.doudizhu.message.ResApplyMsg;
import com.idealighter.game.games.doudizhu.message.ResCallCardMsg;
import com.idealighter.game.games.doudizhu.message.ResCancelApplyMsg;
import com.idealighter.game.games.doudizhu.message.ResDealCardsMsg;
import com.idealighter.game.games.doudizhu.message.ResDoubleMsg;
import com.idealighter.game.games.doudizhu.message.ResEnterGameHallMsg;
import com.idealighter.game.games.doudizhu.message.ResEnterRoomMsg;
import com.idealighter.game.games.doudizhu.message.ResEnterTableMsg;
import com.idealighter.game.games.doudizhu.message.ResGameOverMsg;
import com.idealighter.game.games.doudizhu.message.ResGameStartMsg;
import com.idealighter.game.games.doudizhu.message.ResHiddenCardsMsg;
import com.idealighter.game.games.doudizhu.message.ResMatchInfoUpdateMsg;
import com.idealighter.game.games.doudizhu.message.ResMatchRunsInfoUpdateMsg;
import com.idealighter.game.games.doudizhu.message.ResMatchRunsOverMsg;
import com.idealighter.game.games.doudizhu.message.ResPlayCardsMsg;
import com.idealighter.game.games.doudizhu.message.ResPreEliminationMsg;
import com.idealighter.game.games.doudizhu.message.ResPromptMsg;
import com.idealighter.game.games.doudizhu.message.ResRankRewardInfoMsg;
import com.idealighter.game.games.doudizhu.message.ResShoutMsg;
import com.idealighter.game.games.doudizhu.message.ResTableSeatInfosUpdateMsg;
import com.idealighter.game.games.doudizhu.message.ResWithdrawMsg;
import com.idealighter.game.games.doudizhu.struct.DouDiZhuCard;
import com.idealighter.game.games.doudizhu.struct.DouDiZhuCardsType;
import com.idealighter.game.games.doudizhu.struct.DouDiZhuMatch;
import com.idealighter.game.games.doudizhu.struct.DouDiZhuRoom;
import com.idealighter.game.games.doudizhu.struct.DouDiZhuSeat;
import com.idealighter.game.games.doudizhu.struct.DouDiZhuTable;
import com.idealighter.game.message.core.ResMessage;
import com.idealighter.game.player.manager.PlayerMsgWriter;
import com.idealighter.game.player.struct.Player;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 斗地主消息管理工具类 .
 * 
 * @date 2015年8月8日 下午6:50:55
 *
 */
@Singleton
public class DouDiZhuMsgMgr {

  @Inject
  private PlayerMsgWriter msgWriter;
  @Inject
  private DouDiZhuDataMgr dataMgr;
  @Inject
  private DoudizhuMatchRoomDic matchRoomDic;
  @Inject
  private DoudizhuRoomTypeDic roomTypeDic;
  @Inject
  private ItemDic itemDic;


  /**
   * 发送进入游戏大厅消息 .
   * 
   * @param player 玩家.
   */
  public void sendEnterGameHallMsg(Player player) {
    ResEnterGameHallMsg msg = new ResEnterGameHallMsg();

    Collection<DouDiZhuRoom> rooms = dataMgr.rooms();
    for (DouDiZhuRoom room : rooms) {
      DoudizhuMatchRoomDomain roomDom = matchRoomDic.get(room.getId().intValue());
      RoomTypeDetailInfo roomTypeDetailInfo = new RoomTypeDetailInfo();
      if (roomDom.getIsActive() != 1) {
        continue;
      }
      roomTypeDetailInfo.setType(roomDom.getType());
      roomTypeDetailInfo.setTypeName(roomTypeDic.map().get(roomDom.getType()).getName());

      RoomInfo roomInfo = new RoomInfo();
      roomInfo.setRoomId(room.getId().intValue());
      roomInfo.setName(roomDom.getName());
      roomInfo.setType(roomDom.getType());

      roomInfo.setFee(roomDom.getGold());
      roomInfo.setTicket(roomDom.getTickets());
      roomInfo.setTicketName(itemDic.get(roomDom.getTickets()).getName());
      MatchInfo matchInfo = new MatchInfo();
      if (room.curMatch != null) {
        matchInfo = matchInfo(room.curMatch);
      }
      roomInfo.setMatchInfo(matchInfo);
      roomTypeDetailInfo.getRooms().add(roomInfo);

      msg.getRoomTypes().add(roomTypeDetailInfo);
    }

    msgWriter.writeMsg(player, msg);
  }

  /**
   * 获取比赛信息 .
   * 
   * @return
   */
  public MatchInfo matchInfo(DouDiZhuMatch match) {
    MatchInfo matchInfo = new MatchInfo();
    matchInfo.setAppliedNum(match.applyNum);
    matchInfo.setLeftTime((int) ((match.matchTime - System.currentTimeMillis()) / 1000));
    matchInfo.setMatchTime((int) (match.matchTime / 1000));
    matchInfo.setMatchNum(match.matchNum);
    matchInfo.setType(match.type);
    matchInfo.setReward(matchRoomDic.get(match.room.getId().intValue()).getReward());

    return matchInfo;
  }


  /**
   * 发送进入房间消息 .
   * 
   * @param player 玩家.
   * @param room .
   */
  public void sendEnterRoomMsg(Player player, DouDiZhuRoom room) {
    ResEnterRoomMsg msg = new ResEnterRoomMsg();
    msg.setRoomId(room.getId().intValue());
    msg.setApply(room.curMatch.appliedPlayers.contains(player.getId()) ? 1 : 0);
    msg.setMatchInfo(matchInfo(room.curMatch));
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 发送进入桌子消息 .
   * 
   * @param seat 座位信息.
   */
  public void sendEnterTableMsg(DouDiZhuSeat seat) {
    ResEnterTableMsg msg = new ResEnterTableMsg();
    msgWriter.writeMsg(seat.getPlayerId(), msg);
  }

  /**
   * 发送报名结果 .
   * 
   * @param player 玩家.
   * @param res (0:成功,1:已经报过名不能报名本比赛,2:人数足够已经开赛) .
   */
  public void sendApplyMsg(Player player, int res) {
    ResApplyMsg msg = new ResApplyMsg();
    msg.setRes(res);
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 向同桌的玩家发送叫牌结果消息 .
   * 
   * @param seat 座位信息. 叫牌的座位 .
   * @param callOver . 叫牌是否结束 .
   */
  public void sendCallCardMsg(DouDiZhuSeat seat, boolean callOver) {
    ResCallCardMsg msg = new ResCallCardMsg();
    msg.setPlayerId(seat.getPlayerId());

    DouDiZhuSeat landlord = seat.table.landlord();
    msg.setLandlord(callOver && landlord != null ? landlord.getPlayerId() : 0);
    msg.setLandlordOrder(callOver && landlord != null ? landlord.getOrder() : 0);
    msg.setOrder(seat.getOrder());
    msg.setType(seat.callType.type);
    msg.setNextCallOrder(seat.table.nextCallOrder);

    sendTableMsg(seat.table, msg);
  }

  /**
   * 向同桌的玩发送该牌桌的底牌消息 .
   * 
   * @param table .
   */
  public void sendHiddenCardsMsg(DouDiZhuTable table) {
    // 底牌
    List<DouDiZhuCard> hiddenCards = table.hiddenCards();
    List<Integer> hiddenCardIds = new ArrayList<>(hiddenCards.size());
    for (DouDiZhuCard card : hiddenCards) {
      hiddenCardIds.add(card.ordinal());
    }

    ResHiddenCardsMsg msg = new ResHiddenCardsMsg();
    msg.getCards().addAll(hiddenCardIds);

    sendTableMsg(table, msg);
  }

  /**
   * 向同桌的每个玩家发送自己的牌消息 .
   * 
   * @param table .
   */
  public void sendDealCardsMsg(DouDiZhuTable table) {

    for (DouDiZhuSeat seat : table.seats) {
      ResDealCardsMsg msg = new ResDealCardsMsg();
      for (DouDiZhuCard card : seat.cards) {
        msg.getCards().add(card.ordinal());
      }
      msg.setFirstCallOrder(table.nextCallOrder);
      msgWriter.writeMsg(seat.getPlayerId(), msg);
    }
  }

  /**
   * 向同桌的玩家发送出的牌 .
   * 
   * @param table .
   * @param seat 座位信息. 出牌的玩家 .
   * @param cards .
   */
  public void sendPlayCardsMsg(DouDiZhuTable table, DouDiZhuSeat seat, List<DouDiZhuCard> cards,
      DouDiZhuCardsType cardsType) {
    ResPlayCardsMsg msg = new ResPlayCardsMsg();
    msg.setPlayerId(seat.getPlayerId());
    msg.setCards(cards.stream().map((card) -> card.ordinal()).collect(Collectors.toList()));
    msg.setCardsType(cardsType.type);
    msg.setNextPlayOrder(table.nextPlayOrder);
    msg.setOrder(seat.getOrder());
    sendTableMsg(table, msg);
  }

  /**
   * 向同桌的玩家发送放弃出牌消息 .
   * 
   * @param table .
   * @param order .
   */
  public void sendAbandonMsg(DouDiZhuTable table, int order) {
    ResAbandonMsg msg = new ResAbandonMsg();
    msg.setOrder(order);
    msg.setNextPlayOrder(table.nextPlayOrder);
    sendTableMsg(table, msg);
  }

  /**
   * 向同桌的玩家发送游戏结束消息 .
   * 
   * @param table .
   * @param landlord .
   * @param landlordCedits .
   * @param farmer1 .
   * @param farmer1Cedits .
   * @param farmer2 .
   * @param farmer2Cedits .
   */
  public void sendGameOverMsg(DouDiZhuTable table, DouDiZhuSeat landlord, long landlordCedits,
      DouDiZhuSeat farmer1, long farmer1Cedits, DouDiZhuSeat farmer2, long farmer2Cedits) {

    BillInfo landlordBill = new BillInfo();
    landlordBill.setPlayerId(landlord.getPlayerId());
    landlordBill.setPlayerName(landlord.getPlayerName());
    landlordBill.setOrder(landlord.getOrder());
    landlordBill.setCedits(landlordCedits);

    BillInfo farmer1BIll = new BillInfo();
    farmer1BIll.setPlayerId(farmer1.getPlayerId());
    farmer1BIll.setPlayerName(farmer1.getPlayerName());
    farmer1BIll.setOrder(farmer1.getOrder());
    farmer1BIll.setCedits(farmer1Cedits);

    BillInfo farmer2BIll = new BillInfo();
    farmer2BIll.setPlayerId(farmer2.getPlayerId());
    farmer2BIll.setPlayerName(farmer2.getPlayerName());
    farmer2BIll.setOrder(farmer2.getOrder());
    farmer2BIll.setCedits(farmer2Cedits);

    ResGameOverMsg msg = new ResGameOverMsg();
    msg.getBills().add(landlordBill);
    msg.getBills().add(farmer1BIll);
    msg.getBills().add(farmer2BIll);
    sendTableMsg(table, msg);
  }

  /**
   * 发送退出桌子消息 .
   * 
   * @param seat 座位信息.
   */
  public void sendWithdrawMsg(DouDiZhuSeat seat) {
    msgWriter.writeMsg(seat.getPlayerId(), new ResWithdrawMsg());
  }

  /**
   * 发送提示的牌信息 .
   * 
   * @param player 玩家.
   * @param cards .
   */
  public void sendPromptMsg(Player player, List<DouDiZhuCard> cards) {
    ResPromptMsg msg = new ResPromptMsg();
    if (cards != null) {
      msg.setCards(cards.stream().map((card) -> card.ordinal()).collect(Collectors.toList()));
    }

    msgWriter.writeMsg(player, msg);
  }

  /**
   * 发送玩家加倍消息 .
   * 
   * @param seat 座位信息.
   */
  public void sendDoubleMsg(DouDiZhuSeat seat, boolean doubled) {
    ResDoubleMsg msg = new ResDoubleMsg();
    msg.setPlayerId(seat.getPlayerId());
    msg.setDoubled((byte) (doubled ? 1 : 0));
    msg.setOrder(seat.getOrder());
    sendTableMsg(seat.table, msg);
  }

  /**
   * 发送比赛信息变化,在比赛中的玩家不需要通知 .
   * 
   * @param match .
   */
  public void sendMatchInfoUpdateMsg(DouDiZhuMatch match) {
    ResMatchInfoUpdateMsg msg = new ResMatchInfoUpdateMsg();
    msg.setMatchInfo(matchInfo(match));

    for (Long playerId : match.room.getPlayers()) {
      if (dataMgr.getPlayerSeat(playerId) == null) {
        msgWriter.writeMsg(playerId, msg);
      }
    }
  }

  /**
   * 发送排名奖励消息 .
   * 
   * @param seat 座位信息.
   * @param rewards .
   */
  public void sendRankRewardInfoMsg(DouDiZhuSeat seat, List<Reward> rewards) {
    ResRankRewardInfoMsg msg = new ResRankRewardInfoMsg();
    msg.setRank(seat.rank);
    if (rewards != null) {
      for (Reward reward : rewards) {
        RankRewardInfo rewardInfo = new RankRewardInfo();
        rewardInfo.setId(reward.getId());
        rewardInfo.setNum(reward.getNum());
        msg.getRewards().add(rewardInfo);
      }
    }

    msgWriter.writeMsg(seat.getPlayerId(), msg);
  }

  /**
   * 桌子座位信息更新 .
   * 
   * @param table .
   */
  public void sendTableSeatInfosUpdateMsg(DouDiZhuTable table) {
    ResTableSeatInfosUpdateMsg msg = new ResTableSeatInfosUpdateMsg();
    DouDiZhuMatch match = table.match;
    DoudizhuMatchRoomDomWrapper matchRoomDom = matchRoomDic.get(match.room.getId().intValue());

    msg.setRunsPlayerNum(
        match.runs == 0 ? matchRoomDom.getNum() : matchRoomDom.getFinalsAdvanceNum(match.runs));
    for (DouDiZhuSeat seat : table.seats) {
      msg.getSeatInfos().add(seat.getSeatInfo());
    }

    sendTableMsg(table, msg);
  }

  /**
   * 发送游戏开始消息 .
   * 
   * @param table .
   */
  public void sendGameStartMsg(DouDiZhuTable table) {
    ResGameStartMsg msg = new ResGameStartMsg();
    DouDiZhuMatch match = table.match;
    DoudizhuMatchRoomDomWrapper matchRoomDom = matchRoomDic.get(match.room.getId().intValue());

    msg.setRunsPlayerNum(
        match.runs == 0 ? matchRoomDom.getNum() : matchRoomDom.getFinalsAdvanceNum(match.runs));
    for (DouDiZhuSeat seat : table.seats) {
      msg.getSeatInfos().add(seat.getSeatInfo());
    }
    msg.setAntes(table.baseCedits);
    sendTableMsg(table, msg);
  }

  /**
   * 发送取消申请消息 .
   * 
   * @param player 玩家.
   */
  public void sendCancelApplyMsg(Player player) {
    msgWriter.writeMsg(player, new ResCancelApplyMsg());
  }

  /**
   * 发送比赛轮数信息更新 .
   * 
   * @param match .
   */
  public void sendMatchRunsUpdateMsg(DouDiZhuMatch match) {
    ResMatchRunsInfoUpdateMsg msg = new ResMatchRunsInfoUpdateMsg();
    msg.setRuns(match.runs);
    DoudizhuMatchRoomDomWrapper matchRoomDomWrapper =
        matchRoomDic.get(match.room.getId().intValue());

    // 正在比赛的桌子数
    int matchIngTables = 0;
    if (match.runs == 0) { // 预赛
      for (DouDiZhuTable t : match.tables) {
        if (!t.preliminaryOver) {
          matchIngTables++;
        }
      }
    } else { // 决赛
      int finalsRunsTimes = matchRoomDomWrapper.getFinalsRunsTimes();
      for (DouDiZhuTable t : match.tables) {
        if (t.completedFinalsRuns < finalsRunsTimes) {
          matchIngTables++;
        }
      }
    }

    msg.setTables(matchIngTables);
    msg.getNums().add(match.matchNum);
    msg.getNums().addAll(matchRoomDomWrapper.getFinalsAdvanceNumsData());

    sendMatchMsg(match, msg);
  }

  /**
   * 发送比赛轮数结束消息 .
   * 
   * @param table .
   */
  public void sendMatchRunsOverMsg(DouDiZhuTable table) {
    sendTableMsg(table, new ResMatchRunsOverMsg());
  }

  /**
   * 发送喊话消息 .
   * 
   * @param seat 座位信息.
   * @param type . 1:嘲讽,2:催牌,3:赞扬 .
   */
  public void sendShoutMs(DouDiZhuSeat seat, int type) {
    ResShoutMsg msg = new ResShoutMsg();
    msg.setOrder(seat.getOrder());
    msg.setType(type);
    sendTableMsg(seat.table, msg);
  }

  /**
   * 发送配桌失败消息 .
   * 
   * @param table .
   */
  public void sendAssigneSeatsFailMsg(DouDiZhuTable table) {
    // sendTableMsg(table, new ResAssigneSeatsFailMsg());
  }

  /**
   * 发送预赛淘汰消息 .
   * 
   * @param seat 座位信息.
   * @param players . 被通知的玩家 .
   */
  public void sendPreEliminationMsg(DouDiZhuSeat seat, Collection<Long> players) {
    ResPreEliminationMsg msg = new ResPreEliminationMsg();
    msg.setOrder(seat.getOrder());
    for (Long playerId : players) {
      msgWriter.writeMsg(playerId, msg);
    }
  }

  /**
   * 向同桌的玩家(包括自己)发送消息 .
   * 
   * @param table .
   * @param msg .
   */
  public void sendTableMsg(DouDiZhuTable table, ResMessage msg) {
    List<? extends AbstractSeat> seats = table.seats();
    for (int i = 0; i < seats.size(); i++) {
      AbstractSeat seat = seats.get(i);
      long playerId = seat.getPlayerId();
      if (playerId > 0) {
        msgWriter.writeMsg(playerId, msg);
      }
    }
  }

  /**
   * 向正在比赛的人发送消息 .
   * 
   * @param match .
   * @param msg .
   */
  public void sendMatchMsg(DouDiZhuMatch match, ResMessage msg) {
    for (DouDiZhuSeat seat : match.playerSeats()) {
      if (seat.getPlayerId() > 0) {
        msgWriter.writeMsg(seat.getPlayerId(), msg);
      }
    }
  }

}
